'''
struct是Python标准库中的二进制数据处理模块，用于在Python值与C结构体之间进行转换。
作用：1.序列化 2.内存精确控制
<【大小端】
I【数据类型】I=unsigned(4字节） int ,Q=uint64（8字节）
数据宽度 4/8字节
3.直接内存操作
    pack_into()直接修改预分配内存区域
    unpack_from（）获取
'''
import struct
from enum import Enum
from typing import Dict, Any, Optional, List, Tuple

from src.utils.parser import Parser


class PageType(Enum):
    """页面类型枚举"""
    INDEX = 1  # 索引页
    DATA = 2   # 数据页
    UNDO = 3   # 撤销日志页
    SYSTEM = 4 # 系统页

class Page:
    """数据库页面的基本单位
    
    页面是数据库存储的基本单位，每个页面有固定大小，包含页头、数据区和页尾
    """
    # 默认页面大小为16KB，与InnoDB一致
    DEFAULT_PAGE_SIZE = 16 * 1024  # 16KB

    def __init__(self, page_id: int, page_type: PageType, size: int = DEFAULT_PAGE_SIZE):
        self.page_id = page_id
        self.page_type = page_type
        self.size = size
        self.dirty = False  # 脏页标记，表示页面是否被修改
        self.pin_count = 0  # 引用计数，用于缓冲池管理
        self.data = bytearray(size)  # 页面数据
        self.lsn = 0  # 日志序列号，用于恢复
        # 建立与缓冲池的双向引用（运行时注入，避免循环导入）
        import threading
        self._buffer_pool = None
        self._lock = threading.RLock()
    
    def get_data(self) -> bytearray:
        """获取页面数据"""
        return self.data
    
    def set_data(self, data: bytearray) -> None:
        """设置页面数据"""
        if len(data) > self.size:
            raise ValueError(f"数据大小({len(data)})超过页面大小({self.size})")
        self.data[:len(data)] = data
        self.dirty = True
    
    def is_dirty(self) -> bool:
        """检查页面是否为脏页"""
        return self.dirty
    
    def set_dirty(self, dirty: bool = True) -> None:
        """设置页面脏页状态"""
        self.dirty = dirty
    
    def pin(self) -> None:
        """增加页面引用计数"""
        self.pin_count += 1
    
    def unpin(self) -> None:
        """减少页面引用计数"""
        if self.pin_count > 0:
            self.pin_count -= 1

    def get_pin_count(self) -> int:
        """获取页面引用计数"""
        return self.pin_count
    
    def set_lsn(self, lsn: int) -> None:
        """设置日志序列号"""
        self.lsn = lsn
    
    def get_lsn(self) -> int:
        """获取日志序列号"""
        return self.lsn
    
    def attach_buffer_pool(self, buffer_pool) -> None:
        """由缓冲池在装载/创建页面时注入自身，建立反向引用"""
        self._buffer_pool = buffer_pool
    
    def release(self) -> None:
        """释放页面引用（等价于 Java 的 PageImpl.release()）"""
        if self._buffer_pool is not None:
            # 释放一次引用计数
            self._buffer_pool.unpin_page(self.page_id)
    
    def flush(self) -> bool:
        """将页面刷新到磁盘"""
        if self._buffer_pool is None:
            return False
        return self._buffer_pool.flush_page(self.page_id)
    
    def lock(self) -> None:
        """加锁（与 Java 的 lock() 行为一致）"""
        self._lock.acquire()
    
    def unlock(self) -> None:
        """解锁（与 Java 的 unlock() 行为一致）"""
        try:
            self._lock.release()
        except RuntimeError:
            # 如果未持有锁，忽略
            pass
    
    def get_page_number(self) -> int:
        """与 Java Page 接口对齐的页号访问器"""
        return self.page_id
    
class DataPage(Page):
    """数据页实现
    
    数据页存储表的实际记录数据
    """
    # 页头大小（字节）
    HEADER_SIZE = 120
    
    # 页尾大小（字节）
    TRAILER_SIZE = 0  # 修改为0，去掉页尾
    
    def __init__(self, page_id: int, size: int = Page.DEFAULT_PAGE_SIZE):
        super().__init__(page_id, PageType.DATA, size)
        # 初始化页头
        self._init_header()
        
    def _init_header(self) -> None:
        """初始化页头"""
        # 页头格式：
        # - 页ID (8字节)
        # - 前一页ID (8字节)
        # - 后一页ID (8字节)
        # - 记录数量 (4字节)
        # - 空闲空间偏移量 (4字节)
        # - 最后一条记录的偏移量 (4字节)
        # - 页类型 (4字节)
        # - LSN (8字节)
        # - 校验和 (4字节)
        # - 保留字节 (68字节)

        struct.pack_into("<QQQIIIIQI", self.data, 0,
                        self.page_id,  # 页ID
                        0,              # 前一页ID
                        0,              # 后一页ID
                        0,              # 记录数量
                        self.HEADER_SIZE,  # 空闲空间偏移量
                        0,              # 最后一条记录的偏移量
                        self.page_type.value,  # 页类型
                        0,              # LSN
                        0)              # 校验和
    
    def get_record_count(self) -> int:
        """获取页面中的记录数量"""
        return struct.unpack_from("<I", self.data, 24)[0]
    
    def set_record_count(self, count: int) -> None:
        """设置页面中的记录数量"""
        struct.pack_into("<I", self.data, 24, count)
        self.dirty = True
    
    def get_free_space_offset(self) -> int:
        """获取空闲空间的起始偏移量"""
        free_space=struct.unpack_from("<I", self.data, 28)[0]
        return struct.unpack_from("<I", self.data, 28)[0]
    
    def set_free_space_offset(self, offset: int) -> None:
        """设置空闲空间的起始偏移量"""
        struct.pack_into("<I", self.data, 28, offset)
        self.dirty = True
    
    def get_free_space_size(self) -> int:
        """获取页面中的空闲空间大小"""
        free_offset = self.get_free_space_offset()
        return self.size - free_offset  # 去掉 - self.TRAILER_SIZE
    
    def insert_record(self, record: bytes) -> int:
        """
        插入一条记录，返回记录的偏移量
        由data_manager调用，被field，table,btree,node调用
        """
        record_len = len(record)
        if record_len > self.get_free_space_size():
            raise ValueError("页面空间不足，无法插入记录")
        
        # 获取当前空闲空间偏移量
        offset = self.get_free_space_offset()
        
        # 写入记录长度和记录数据
        self.data[offset:offset+record_len] = record
        
        # 更新空闲空间偏移量
        new_offset = offset + record_len
        self.set_free_space_offset(new_offset)
        
        # 更新记录数量
        self.set_record_count(self.get_record_count() + 1)
        
        # 更新最后一条记录的偏移量
        struct.pack_into("<I", self.data, 32, offset)

        self.dirty = True
        return offset
    # # 以下没用到
    # def get_record(self, offset: int) -> bytes:
    #     """根据偏移量获取记录"""
    #     # 检查偏移量是否有效
    #     if offset < self.HEADER_SIZE or offset >= self.get_free_space_offset():
    #         raise ValueError(f"Invalid record offset: {offset}")
    #
    #     # 检查是否有足够的空间读取记录长度
    #     if offset + 2 > self.get_free_space_offset():
    #         raise ValueError("Not enough space to read record length")
    #
    #     record_len = struct.unpack_from("<H", self.data, offset)[0]
    #
    #     # 验证记录长度是否合理
    #     if record_len == 0:
    #         raise ValueError("Record has been deleted or is invalid")
    #
    #     if record_len > 4000:  # 合理的最大记录长度
    #         raise ValueError(f"Invalid record length: {record_len}")
    #
    #     # 检查是否有足够的空间读取完整记录
    #     if offset + 2 + record_len > self.get_free_space_offset():
    #         raise ValueError("Not enough space to read complete record")
    #
    #     return bytes(self.data[offset+2:offset+2+record_len])
    # def update_record(self, offset: int, record: bytes) -> bool:
    #     """更新指定偏移量的记录"""
    #     old_len = struct.unpack_from("<H", self.data, offset)[0]
    #     new_len = len(record)
    #
    #     # 如果新记录长度小于等于旧记录长度，可以直接覆盖
    #     if new_len <= old_len:
    #         struct.pack_into("<H", self.data, offset, new_len)
    #         self.data[offset+2:offset+2+new_len] = record
    #         # 清空剩余空间
    #         if new_len < old_len:
    #             self.data[offset+2+new_len:offset+2+old_len] = b'\x00' * (old_len - new_len)
    #         self.dirty = True
    #         return True
    #     else:
    #         # 如果新记录长度大于旧记录长度，检查是否有足够空间
    #         extra_space_needed = new_len - old_len
    #         if extra_space_needed > self.get_free_space_size():
    #             return False
    #
    #         # 简化实现：直接更新记录长度和数据
    #         # 在实际数据库中会有更复杂的空间管理和碎片整理
    #         struct.pack_into("<H", self.data, offset, new_len)
    #
    #         # 如果需要更多空间，向后移动数据
    #         if extra_space_needed > 0:
    #             # 获取当前使用的空间大小
    #             used_space = struct.unpack_from("<I", self.data, 32)[0]
    #
    #             # 移动offset之后的数据
    #             move_start = offset + 2 + old_len
    #             move_end = used_space
    #             if move_start < move_end:
    #                 move_data = bytes(self.data[move_start:move_end])
    #                 self.data[move_start + extra_space_needed:move_end + extra_space_needed] = move_data
    #
    #             # 更新已使用空间
    #             struct.pack_into("<I", self.data, 32, used_space + extra_space_needed)
    #
    #         # 写入新记录数据
    #         self.data[offset+2:offset+2+new_len] = record
    #
    #         self.dirty = True
    #         return True
    #
    # def delete_record(self, offset: int) -> bool:
    #     """删除指定偏移量的记录"""
    #     # 简单标记删除，实际空间不回收（真实实现中应该有空间回收机制）
    #     record_len = struct.unpack_from("<H", self.data, offset)[0]
    #     struct.pack_into("<H", self.data, offset, 0)  # 将长度设为0表示删除
    #
    #     # 更新记录数量
    #     self.set_record_count(self.get_record_count() - 1)
    #     self.dirty = True
    #     return True

class IndexPage(Page):
    """索引页实现
    
    索引页存储B+树索引节点
    """
    # 页头大小（字节）
    HEADER_SIZE = 120
    
    def __init__(self, page_id: int, size: int = Page.DEFAULT_PAGE_SIZE):
        super().__init__(page_id, PageType.INDEX, size)
        # 初始化页头
        self._init_header()
        
    def _init_header(self) -> None:
        """初始化页头"""
        # 页头格式：
        # - 页ID (8字节)
        # - 父节点页ID (8字节)
        # - 前一个兄弟节点页ID (8字节)
        # - 后一个兄弟节点页ID (8字节)
        # - 键值对数量 (4字节)
        # - 节点级别 (4字节，0表示叶子节点)
        # - 空闲空间偏移量 (4字节)
        # - 页类型 (4字节)
        # - LSN (8字节)
        # - 校验和 (4字节)
        # - 保留字节 (60字节)
        struct.pack_into("<QQQQIIIIQI", self.data, 0,
                        self.page_id,  # 页ID
                        0,              # 父节点页ID
                        0,              # 前一个兄弟节点页ID
                        0,              # 后一个兄弟节点页ID
                        0,              # 键值对数量
                        0,              # 节点级别
                        self.HEADER_SIZE,  # 空闲空间偏移量
                        self.page_type.value,  # 页类型
                        0,              # LSN
                        0)              # 校验和
    
    def is_leaf(self) -> bool:
        """判断是否为叶子节点"""
        return struct.unpack_from("<I", self.data, 36)[0] == 0
    
    def set_leaf(self, is_leaf: bool) -> None:
        """设置节点是否为叶子节点"""
        level = 0 if is_leaf else 1
        struct.pack_into("<I", self.data, 36, level)
        self.dirty = True
    
    def get_key_count(self) -> int:
        """获取节点中的键值对数量"""
        return struct.unpack_from("<I", self.data, 32)[0]
    
    def set_key_count(self, count: int) -> None:
        """设置节点中的键值对数量"""
        struct.pack_into("<I", self.data, 32, count)
        self.dirty = True
    
    def get_parent_page_id(self) -> int:
        """获取父节点页ID"""
        return struct.unpack_from("<Q", self.data, 8)[0]
    
    def set_parent_page_id(self, page_id: int) -> None:
        """设置父节点页ID"""
        struct.pack_into("<Q", self.data, 8, page_id)
        self.dirty = True